﻿using Abp.Domain.Repositories;
using Choucius.Boilerplate9.Common;
using Choucius.Boilerplate9.Enum;
using Choucius.Boilerplate9.PlasticContainers;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Choucius.Boilerplate9.UR5002
{
    /// <summary>
    /// UR5002桌面式RFID读写器
    /// </summary>
    public class UR5002AppService : IUR5002AppService
    {
        private readonly IRepository<PlasticContainer, Guid> _plasticContainerRepository;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="plasticContainerRepository"></param>
        public UR5002AppService(IRepository<PlasticContainer, Guid> plasticContainerRepository)
        {
            _plasticContainerRepository = plasticContainerRepository;
        }

        /// <summary>
        /// 调用UR5002读写器读取一次RFID标签
        /// </summary>
        /// <returns></returns>
        public List<string> UR5002Read()
        {
            // 连接UR5002
            int port = 0;       // 端口：COM4
            byte comAddr = 255; // COM地址
            byte baud = 5;      // 波特率：
            int portHandle = 0; // 
            int openReturn = UR5002Basic.AutoOpenComPort(ref port, ref comAddr, baud, ref portHandle);
            if (openReturn != 0)
            {
                throw new Exception("串口通讯错误");
            }

            int i;
            int CardNum = 0;
            int Totallen = 0;
            int EPClen, m;
            byte[] EPC = new byte[5000];
            int CardIndex;
            string temps;
            string s, sEPC;
            bool isonlistview;
            byte AdrTID = 0;
            byte LenTID = 0;
            byte TIDFlag = 0;
            var list = new List<string>();
            int fCmdRet = UR5002Basic.Inventory_G2(ref comAddr, AdrTID, LenTID, TIDFlag, EPC, ref Totallen, ref CardNum, portHandle);
            if ((fCmdRet == 1) | (fCmdRet == 2) | (fCmdRet == 3) | (fCmdRet == 4) | (fCmdRet == 0xFB))//代表已查找结束，
            {
                byte[] daw = new byte[Totallen];
                Array.Copy(EPC, daw, Totallen);
                temps = ByteArrayToHexString(daw);
                m = 0;
                if (CardNum == 0)
                {
                    return new List<string>();
                }
                for (CardIndex = 0; CardIndex < CardNum; CardIndex++)
                {
                    EPClen = daw[m];
                    sEPC = temps.Substring(m * 2 + 2, EPClen * 2);
                    sEPC = RFID.GetRFIDfromEPC(sEPC);
                    m = m + EPClen + 1;
                    if (sEPC.Length != EPClen * 2)
                        continue;

                    if (!list.Contains(sEPC))
                    {
                        list.Add(sEPC);
                    }
                }
            }

            // 关闭UR5002的连接
            int closeReturn = UR5002Basic.CloseSpecComPort(port);
            if (closeReturn != 0)
            {
                throw new Exception("串口关闭错误");
            }
            return list;
        }

        /// <summary>
        /// 调用UR5002读写器写入一个RFID标签，并保存标签信息
        /// </summary>
        /// <returns></returns>
        public async Task UR5002WriteAndSaveAsync(string sn)
        {
            // 连接UR5002
            int port = 0;       // 端口：COM4
            byte comAddr = 255; // COM地址
            byte baud = 5;      // 波特率：
            int portHandle = 0; // 
            int openReturn = UR5002Basic.AutoOpenComPort(ref port, ref comAddr, baud, ref portHandle);
            if (openReturn != 0)
            {
                throw new Exception("串口通讯错误");
            }
            //OpenUR5002Port(port);

            // 从UR5002写入RFID标签EPC
            byte[] password = HexStringToByteArray("00000000");
            byte[] writeEPC = HexStringToByteArray(sn);
            byte writeEPClen = Convert.ToByte(sn.Length / 2);
            int errorCode = -1;
            int writeReturn = UR5002Basic.WriteEPC_G2(ref comAddr, password, writeEPC, writeEPClen, ref errorCode, portHandle);
            if (writeReturn != 0)
            {
                throw new Exception("EPC写入失败");
            }

            // 关闭UR5002的连接
            int closeReturn = UR5002Basic.CloseSpecComPort(port);
            if (closeReturn != 0)
            {
                throw new Exception("串口关闭错误");
            }

            // 保存
            var entity = new PlasticContainer();
            entity.RFID = sn;
            entity.Status = LabelStatus.Undefined;
            entity.CreationTime = DateTime.Now;
            entity.CreatorUserId = 1;
            await _plasticContainerRepository.InsertAsync(entity); // 使用InsertAsync方法保存实体
        }

        private string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
            return sb.ToString().ToUpper();
        }

        private byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
                buffer[i / 2] = Convert.ToByte(s.Substring(i, 2), 16);
            return buffer;
        }

        private string GetReturnCodeDesc(int cmdRet)
        {
            switch (cmdRet)
            {
                case 0x00:
                    return "操作成功";
                case 0x01:
                    return "询查时间结束前返回";
                case 0x02:
                    return "指定的询查时间溢出";
                case 0x03:
                    return "本条消息之后，还有消息";
                case 0x04:
                    return "读写模块存储空间已满";
                case 0x05:
                    return "访问密码错误";
                case 0x09:
                    return "销毁密码错误";
                case 0x0a:
                    return "销毁密码不能为全0";
                case 0x0b:
                    return "电子标签不支持该命令";
                case 0x0c:
                    return "对该命令，访问密码不能为全0";
                case 0x0d:
                    return "电子标签已经被设置了读保护，不能再次设置";
                case 0x0e:
                    return "电子标签没有被设置读保护，不需要解锁";
                case 0x10:
                    return "有字节空间被锁定，写入失败";
                case 0x11:
                    return "不能锁定";
                case 0x12:
                    return "已经锁定，不能再次锁定";
                case 0x13:
                    return "参数保存失败,但设置的值在读写模块断电前有效";
                case 0x14:
                    return "无法调整";
                case 0x15:
                    return "询查时间结束前返回";
                case 0x16:
                    return "指定的询查时间溢出";
                case 0x17:
                    return "本条消息之后，还有消息";
                case 0x18:
                    return "读写模块存储空间已满";
                case 0x19:
                    return "电子不支持该命令或者访问密码不能为0";
                case 0xFA:
                    return "有电子标签，但通信不畅，无法操作";
                case 0xFB:
                    return "无电子标签可操作";
                case 0xFC:
                    return "电子标签返回错误代码";
                case 0xFD:
                    return "命令长度错误";
                case 0xFE:
                    return "不合法的命令";
                case 0xFF:
                    return "参数错误";
                case 0x30:
                    return "通讯错误";
                case 0x31:
                    return "CRC校验错误";
                case 0x32:
                    return "返回数据长度有错误";
                case 0x33:
                    return "通讯繁忙，设备正在执行其他指令";
                case 0x34:
                    return "繁忙，指令正在执行";
                case 0x35:
                    return "端口已打开";
                case 0x36:
                    return "端口已关闭";
                case 0x37:
                    return "无效句柄";
                case 0x38:
                    return "无效端口";
                case 0xEE:
                    return "返回指令错误";
                default:
                    return "";
            }
        }
    }
}
